import { Context, Schema, h } from 'koishi'
import { exec } from 'node:child_process'
import path from 'node:path';
import { DateTime } from 'luxon';
import { image } from '@satorijs/element/jsx-runtime';

export const name = 'awa-rst-games101'

export interface Config {
  RasterizerBinPath: string;
  VerboseSessionOutput: boolean;
  VerboseConsoleOutput: boolean;
}

export const Config = Schema.intersect([
  Schema.object(
    {
      RasterizerBinPath: Schema.string()
        .role('textarea')
        .default('/home/bawuyinguo/SSoftwareFiles/games101/cpp_renderer_fork_from_games101_pa03/Assignment3/Code/build')
        .description('Rasterizer二进制文件的绝对路径（不带文件名字，只写父级文件夹）')
    }
  ).description("Rasterizer配置"),
  Schema.object({
    VerboseSessionOutput: Schema.boolean().default(true).description('是否在聊天平台session中输出详细的调试信息'),
    VerboseConsoleOutput: Schema.boolean().default(true).description('是否在控制台输出详细的调试信息')
  }
  ).description("debug settings")
])

export function apply(ctx: Context, config: Config) {
  ctx.command(
    'arst [yaw:number] [pitch:number] [roll:number] [texture_name:string]',
    "调用Games101 作业框架 Rasterizer进行图片渲染"
  )
    .action(async ({ session }, yaw, pitch, roll, texture_name) => {
      const actualTextureName = texture_name || 'grass_block_plus2.png';
      const actualYaw = yaw || 0;
      const actualPitch = pitch || 0;
      const actualRoll = roll || 0;

      const now = DateTime.local().toFormat('yyyy-MM-dd-hh-mm-ss');
      const outputFileName = `output_${actualTextureName}_${now}.png`;
      const textureKeyword = 'texture';

      // 使用配置的父级路径作为工作目录
      const cwd = config.RasterizerBinPath;
      const rasterizerExecutable = './Rasterizer'; // 直接使用 ./Rasterizer

      const command = `${rasterizerExecutable} ${outputFileName} ${textureKeyword} ${actualYaw} ${actualPitch} ${actualRoll} ${actualTextureName}`;


      try {
        if ( config.VerboseConsoleOutput)
          ctx.logger.info(`正在渲染，请稍候... (执行命令: cd ${cwd} && ${command})`);
        // await session.send(`正在渲染，请稍候...`);

        const loadingMsgRes = await session.send(`正在渲染，请稍候...`);

        if ( config.VerboseSessionOutput ){
          await session.send(`(执行命令: cd ${cwd} && ${command})`)
        }

        const { stdout, stderr } = await new Promise<{ stdout: string, stderr: string }>((resolve, reject) => {
          exec(command, { cwd }, (error, stdout, stderr) => { // 传递 cwd 选项
            if (error) {
              reject(error);
              return;
            }
            resolve({ stdout, stderr });
          });
        });

        if (stderr) {
          if ( config.VerboseConsoleOutput)
            ctx.logger.info(`渲染失败，错误信息：${stderr}`);
          await session.send(`渲染失败.`); 
          if ( config.VerboseSessionOutput ){
            await session.send(`stderr的内容：\n${stderr}`);
          }
        } else {
          if ( config.VerboseConsoleOutput )
            ctx.logger.info(`渲染完成，图片已保存为：${outputFileName}。 stdout的内容：${stdout}\n`);
          if ( config.VerboseSessionOutput )
            await session.send(`渲染完成，图片已保存为：${outputFileName}。 stdout的内容：${stdout}\n`);

          let imageResMsg = [];
          imageResMsg.push( h.quote(session.messageId) );
          imageResMsg.push( h.image(`file://${path.join(cwd, "output", outputFileName)}`) );
          await session.send(imageResMsg);
          await session.bot.deleteMessage(session.channelId, loadingMsgRes[0]);

          if ( config.VerboseSessionOutput ){
            await session.send(`stdout的内容：\n${stdout}`);
          }
        }
      } catch (error: any) {

        if ( config.VerboseConsoleOutput)
          ctx.logger.info(`执行命令时发生错误. js try catch到的错误信息：\n${error.message}`);
        await session.send(`执行命令时发生错误`);
        if ( config.VerboseSessionOutput ){
          await session.send(`js try catch到的错误信息：\n${error.message}`);
        }

      }
    });
}